package org.example.controller;

import org.example.model.ChatMessage;
import org.example.service.ChatService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Flux;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

@RestController
@RequestMapping("/api")
public class ChatController {

    private final ChatService chatService;
    private final ObjectMapper objectMapper = new ObjectMapper();

    private static Logger logger = LoggerFactory.getLogger(ChatController.class);

    public ChatController(ChatService chatService) {
        this.chatService = chatService;
    }

    /**
     * 响应用户输入
     * curl -X GET "http://localhost:8080/api/chat?userInput=你好"
     * @param userInput
     * @return
     */
    @GetMapping(path = "/chat")
    public String getResponse(@RequestParam String userInput) {
        try {
            return chatService.getResponse(userInput);
        } catch (Exception e) {
            logger.error("Error during chat processing", e);
            return "{\"error\": \"" + e.getMessage() + "\"}";
        }
    }

    @GetMapping(path = "/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ChatMessage> streamChat(@RequestParam String userInput) {
        try {
            return processChat(userInput, "chat");
        } catch (Exception e) {
            e.printStackTrace();
            return Flux.just(new ChatMessage(
                    "{\"error\": \"" + e.getMessage() + "\"}",
                    false,
                    getCurrentTimestamp()));
        }
    }

    @PostMapping(path = "/chat/assistant", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ChatMessage> assistantChatPost(
            @RequestParam String userInput,
            @RequestParam(required = false) String fileIds, // 修改为接收字符串
            @RequestPart(required = false) MultipartFile file) throws Exception {

        logger.info("收到请求: {}", userInput);
        logger.info("文件IDs原始值: {}", fileIds);

        StringBuilder context = new StringBuilder();

        // 处理文件IDs（如果提供）
        if (fileIds != null && !fileIds.isEmpty()) {
            try {
                // 解析JSON字符串为List<String>
                List<String> fileIdList = objectMapper.readValue(fileIds, new TypeReference<List<String>>() {
                });
                logger.info("解析后文件IDs: {}", fileIdList);

                context.append("参考的文件:\n");

                // 处理每个文件ID
                for (String fileId : fileIdList) {
                    // 从临时存储中获取文件内容
                    context.append("文件ID: ").append(fileId).append("\n");
                }
            } catch (Exception e) {
                logger.error("处理文件ID列表时出错", e);
                context.append("处理文件ID列表时出错: ").append(e.getMessage()).append("\n");
            }
        }

        // 处理直接上传的文件（兼容旧版本）
        if (file != null && !file.isEmpty()) {
            String fileContent = new String(file.getBytes(), StandardCharsets.UTF_8);
            context.append("用户上传了文件: ").append(file.getOriginalFilename())
                    .append("\n\n文件内容:\n").append(fileContent).append("\n\n");
        }

        // 添加用户问题
        context.append("用户问题: ").append(userInput);

        // 处理完整的上下文
        return processChat(context.toString(), "assistant");
    }

    @PostMapping(path = "/upload-file")
    public ResponseEntity<Map<String, Object>> uploadFile(@RequestPart MultipartFile file) {
        try {
            // 生成唯一文件ID
            String fileId = UUID.randomUUID().toString();

            // 获取文件名和大小
            String originalFilename = file.getOriginalFilename();
            String fileName = (originalFilename != null)
                    ? new String(originalFilename.getBytes("ISO-8859-1"), "UTF-8")
                    : "unknown";
            long fileSize = file.getSize();

            // 存储文件内容到临时目录（或内存）
            // 实际生产环境建议使用专门的文件存储服务
            String fileContent = new String(file.getBytes(), StandardCharsets.UTF_8);

            // 简单分析文件：类型、行数等
            Map<String, Object> fileAnalysis = analyzeFile(file, fileContent);

            // 返回文件ID和分析结果
            Map<String, Object> response = new HashMap<>();
            response.put("fileId", fileId);
            response.put("fileName", fileName);
            response.put("fileSize", fileSize);
            response.put("analysis", fileAnalysis);

            // 存储文件信息到服务端缓存或数据库
            // 此处可以使用 Redis、内存缓存或数据库
            // fileService.storeFile(fileId, fileContent);

            return ResponseEntity.ok(response);
        } catch (Exception e) {
            logger.error("文件上传处理失败", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(Map.of("error", e.getMessage()));
        }
    }

    /**
     * 分析文件内容
     */
    private Map<String, Object> analyzeFile(MultipartFile file, String content) {
        Map<String, Object> analysis = new HashMap<>();

        // 检测文件类型
        String fileType = detectFileType(file.getOriginalFilename());
        analysis.put("fileType", fileType);

        // 计算文件行数
        int lineCount = content.split("\n").length;
        analysis.put("lineCount", lineCount);

        // 根据文件类型进行更详细分析
        switch (fileType) {
            case "code":
                // 代码分析：语言类型、函数数量等
                analysis.put("language", detectLanguage(file.getOriginalFilename(), content));
                break;
            case "text":
                // 文本分析：字符数、词数等
                analysis.put("charCount", content.length());
                analysis.put("wordCount", content.split("\\s+").length);
                break;
            // 可添加更多文件类型的处理
        }

        return analysis;
    }

    /**
     * 检测文件类型
     */
    private String detectFileType(String fileName) {
        if (fileName == null)
            return "unknown";

        String extension = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();

        if (Arrays.asList("java", "py", "js", "ts", "c", "cpp", "go", "rb", "php").contains(extension)) {
            return "code";
        } else if (Arrays.asList("txt", "md", "log").contains(extension)) {
            return "text";
        } else if (Arrays.asList("jpg", "jpeg", "png", "gif", "bmp").contains(extension)) {
            return "image";
        } else if (Arrays.asList("pdf", "doc", "docx").contains(extension)) {
            return "document";
        }

        return "unknown";
    }

    /**
     * 检测编程语言
     */
    private String detectLanguage(String fileName, String content) {
        String extension = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();

        switch (extension) {
            case "java":
                return "Java";
            case "py":
                return "Python";
            case "js":
                return "JavaScript";
            case "ts":
                return "TypeScript";
            case "go":
                return "Go";
            default:
                return "Unknown";
        }
    }

    private Flux<ChatMessage> processChat(String userInput, String type) throws Exception {
        String timestamp = getCurrentTimestamp();
        Flux<String> result = null;
        if ("chat".equals(type)) {
            result = chatService.getResponseStream(userInput);
        } else {
            result = chatService.getAssistantResponseStream(userInput);
        }
        return result.map(response -> new ChatMessage(
                response,
                false,
                timestamp))
                .onErrorResume(error -> Flux.just(new ChatMessage(
                        "{\"error\": \"" + error.getMessage() + "\"}",
                        false,
                        timestamp)));
    }

    private String getCurrentTimestamp() {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }
}